//
//  ViewController.swift
//  swift-02
//
//  Created by China Dragon on 2023/8/19.
//

import UIKit

/*
 
 知识点
 
 storyboard本质上是xml文件
 选中Main.storyboard，右键 penAs source code,即可查看xml文件
 程序一旦被编译后编程二进制文件了，不是xml
 
 
 在swift中所有的属性和方法都是全局共享的，不需要import，可以直接使用
 
 Xcode调试技巧总结
 https://blog.csdn.net/box_kun/article/details/122617231
 
 Xcode控制台调试常用命令
 https://betheme.net/news/txtlist_i28049v.html?action=onClick
 
 Xcode调试工具Instruments指南
 https://dgrt.cn/a/1535329.html?action=onClick
 */
class ViewController: UIViewController {
    
    
    /*
     赖加载 ，本质上是一个闭包
     
     第一次访问属性的时候会执行后面的()闭包代码，将闭包的结果保存在person属性中，下次再访问，不会再执行闭包
     
     如果没有lazy，会在 initwithcoder方法中调用，当二进制的storyboard被还原成视图控制器对象之后就会被调用
     
    
     */
    
    lazy var p4: Person4 = {
        print("赖加载")
        return Person4()
    }()//()表示执行
    
    //1、演示闭包
    let personFunc = {() -> (Person4) in
        print("赖加载 测试...")
        return Person4()
    }
    
    //赖加载的简单写法
    lazy var p42: Person4 = Person4()
    
    //2、测试懒加载属性
   lazy var demoPerson4: Person4 =  self.personFunc()
    
    
    //定义完成回调属性
    //闭包的返回值可选,?前面是谁代表谁可选
//    var finishedCallBack: () ->()?
    //闭包的属性可选
    var finishedCallBack: ((_  responseData: String) ->())?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
//        test()
//        bibao1()
//        bibao2()
        bibao3()
       
        
    }
    
    func bibao3(){
        //解除循环引用 方法三
       //swift 方法二
        //[unowned self]表示闭包中的self都是 assign -> 如果 self 释放， 闭包中的self 地址不会被修改
        // 与 _unsafe_unretained 类似，如果 self 被释放，同样会会出现野指针
        loadData {[unowned self] responseData in
            print(responseData)
            //闭包中一定要使用self.
            print(self.view)//闭包对self进行强引用
        }
    }
    
    func bibao2(){
        //解除循环引用 方法二
       //swift 方法一
        //[weak self]表示闭包中的self都是弱引用
        loadData {[weak self] responseData in
            print(responseData)
            //闭包中一定要使用self.
            print(self?.view)//闭包对self进行强引用
        }
    }
    
    func bibao1(){
      
        /*
         解除循环引用 方法一 OC：的传统方法
         weak 属性运行时可能会被改变 -> 执行对象一旦被释放，变成nil
         weak 属性不能是let
         */
      
        weak var weakself = self
        
        loadData { responseData in
            print(responseData)
            //闭包中一定要使用self.
//            print(self.view)//闭包对self进行强引用
//            print(weakself?.self)//解除循环引用
            print(weakself.self)//解除循环引用
        }
    }
    
    deinit{
        print("ViewController 销毁了")
    }
    
    /*
        闭包实现循环引用
     */
    //闭包应用场景：异步操作完成后，通过闭包参数传递网络请求结果
    func loadData(finished: @escaping(_ responseData: String) ->()){
        
        //记录完成回调
        finishedCallBack = finished
        
        DispatchQueue.global().async {
            print("模拟异步加载数据")
            
            //主线程回调
            DispatchQueue.main.async {
                print("主线程回调")
                // 如果方法不能在当前方法立即执行，可以通过属性记录，在需要的时候用 执行
//                finished("网络数据内容")
                self.finishedCallBack?("网络数据内容")//存在循环引用
            }
        }
    }
    
    
//    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//        print("touchesBegan ->p4 ：  \(p4)")//验证赖加载, 点击屏幕时会被调用
//        print("touchesBegan ->p42 ：  \(p42)")//验证赖加载, 点击屏幕时会被调用
//        print("touchesBegan -> demoPerson4 ： \(demoPerson4)")//验证赖加载, 点击屏幕时会被调用
//    }
    
    func test(){
        print("viewDidLoad -> \(p4)")//验证赖加载
        //        let p = Person()
        let p = Person(name: "t1", name2: "t2", age: 18)
        print("p 姓名：\(p.name), 年龄：\(p.age)")
        print("--------------")
        
        //        let stu = Student()
        let stu = Student(name: "ss1", name2: "s2", age: 16, no: "011")
        print("stu 姓名：\(stu.name), 年龄：\(stu.age) , 学号：\(stu.no)")
        
        print("--------------")
        
        let p2 = Person2(dic: ["name":"p2","age":22])
        print("p2 姓名：\(p2.name), 年龄：\(p2.age)")
        
        let stu2 = Student2(dic: ["name":"p2","age":22, "no":"002"])
        print("stu2 姓名：\(stu2.name), 年龄：\(stu2.age) , 学号：\(stu2.no)")
        
        print("--------------")
        
        let p3 = Person3(name:"pc3", age: 106)
        print("p 姓名：\(p3?.name), 年龄：\(p3?.age)")
        
        let stu3 = Student3(dic: ["name":"p2","age":22, "no":"002"])
        print("stu3 姓名：\(stu3.name), 年龄：\(stu3.age) , 学号：\(stu3.no)")
        
        let p5 = Person5()
//        p5._name // _name前面没有加 private
        p5.name = "p51"
        print("p51 \(p5.name)")
        print("p5 title \(p5.title)")
        p5.name2 = "p52";
        print("p52 \(p5.name2)")
        
        print("p5 title2 \(p5.title2)")
        print("p5 title3 \(p5.title3)")
        p5.name = "test"
        print("--------------")
        print("p5 title2 \(p5.title2)")
        print("p5 title3 \(p5.title3)")
        /*
         p5 title2 Optional("Mr2 222 p51")
         p5 title3 Optional("Mr3 333 p51")
         --------------
         p5 title2 Optional("Mr2 222 test")
         p5 title3 Optional("Mr3 333 p51") // title3的内容没有变化
         */
        print("--------------")
        
    }


}

 
